package org.lewis.common.jdbc;

import java.sql.*;
import java.util.*;
import java.lang.reflect.*;
import javax.sql.DataSource;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 数据连接管理
 * 
 * @author taiqichao
 * 
 */
public class DBManager {

	private final static Log log = LogFactory.getLog(DBManager.class);
	
	private final static ThreadLocal<Connection> connPoll = new ThreadLocal<Connection>();
	
	private static DataSource dataSource;
	
	private static boolean showSql = false;

	static {
		initDataSource(null);
	}

	/**
	 * 初始化连接池
	 * 
	 */
	private final static void initDataSource(Properties dbProperties) {
		try {
			if (dbProperties == null) {
				dbProperties = new Properties();
				dbProperties.load(DBManager.class
						.getResourceAsStream("/database.local.properties"));
			}
			Properties props = new Properties();
			for (Object key : dbProperties.keySet()) {
				String skey = (String) key;
				if (skey.startsWith("jdbc.")) {
					String name = skey.substring(5);
					props.put(name, dbProperties.getProperty(skey));
					if ("show_sql".equalsIgnoreCase(name)) {
						showSql = "true".equalsIgnoreCase(dbProperties.getProperty(skey));
					}
				}
			}
			dataSource = (DataSource) Class.forName(
					props.getProperty("datasource")).newInstance();
			if (dataSource.getClass().getName().indexOf("c3p0") > 0) {
				System.setProperty("com.mchange.v2.c3p0.management.ManagementCoordinator","com.mchange.v2.c3p0.management.NullManagementCoordinator");
			}
			log.info("Using DataSource : " + dataSource.getClass().getName());
			BeanUtils.populate(dataSource, props);
			Connection conn = getConnection();
			DatabaseMetaData mdm = conn.getMetaData();
			log.info("Connected to " + mdm.getDatabaseProductName() + " "
					+ mdm.getDatabaseProductVersion());
			closeConnection();
		} catch (Exception e) {
			log.error("InitDataSource failed. " + e);
		}
	}

	/**
	 * 断开数据库
	 */
	public final static void closeDataSource() {
		try {
			dataSource.getClass().getMethod("close").invoke(dataSource);
		} catch (NoSuchMethodException e) {
		} catch (Exception e) {
			log.error("Unabled to destroy DataSource.", e);
		}
	}

	/**
	 * 获得连接
	 * 
	 * @return
	 * @throws SQLException
	 */
	public final static Connection getConnection() throws SQLException {
		Connection conn = connPoll.get();
		if (conn == null || conn.isClosed()) {
			conn = dataSource.getConnection();
			connPoll.set(conn);
		}
		return (showSql && !Proxy.isProxyClass(conn.getClass())) ? new debugConnection(
				conn).getConnection()
				: conn;
	}

	/**
	 * 关闭连接
	 */
	public final static void closeConnection() {
		Connection conn = connPoll.get();
		try {
			if (conn != null && !conn.isClosed()) {
				conn.setAutoCommit(true);
				conn.close();
			}
		} catch (SQLException e) {
			log.error("Unabled to close connection", e);
		}
		connPoll.set(null);
	}

	static class debugConnection implements InvocationHandler {

		private final static Log log = LogFactory.getLog(debugConnection.class);

		private Connection conn = null;

		public debugConnection(Connection conn) {
			this.conn = conn;
		}

		/**
		 * Returns the conn.
		 * 
		 * @return Connection
		 */
		public Connection getConnection() {
			return (Connection) Proxy.newProxyInstance(conn.getClass()
					.getClassLoader(), conn.getClass().getInterfaces(), this);
		}

		public Object invoke(Object proxy, Method m, Object[] args)
				throws Throwable {
			try {
				String method = m.getName();
				if ("prepareStatement".equals(method)
						|| "createStatement".equals(method))
					log.info("[SQL]-->" + args[0]);
				return m.invoke(conn, args);
			} catch (InvocationTargetException e) {
				throw e.getTargetException();
			}
		}

	}

}
